﻿using markdown_picture_packer.backend;
using markdown_picture_packer.common.constants;
using markdown_picture_packer.common.enums;
using markdown_picture_packer.common.utils;
using markdown_picture_packer.frontend.panels;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace markdown_picture_packer.frontend.forms
{
    public class ExecuteForm : BaseForm
    {
        private readonly CancellationTokenSource Token = new CancellationTokenSource();
        private readonly SemaphoreSlim ConcurrencySemaphore = new SemaphoreSlim(5); // 限制最大并发数为5
        private ProgressBarPanel Pbp;
        private LogTextPanel Ltp;
        private readonly string BasePath;
        private readonly List<string> FilePaths;
        private readonly List<string> RepeatFileName;
        private readonly bool IsRandomName;
        private readonly bool IsNumberName;
        private readonly bool IsOriginalName;

        public ExecuteForm(List<string> filePaths, string exportPath, string makeNameVal)
        {
            FilePaths = filePaths;
            IsRandomName = makeNameVal.Equals(EnumDictionary.MAKE_NAME_TYPE[MakeNameType.RANDOM]);
            IsNumberName = makeNameVal.Equals(EnumDictionary.MAKE_NAME_TYPE[MakeNameType.NUMBER]);
            IsOriginalName = makeNameVal.Equals(EnumDictionary.MAKE_NAME_TYPE[MakeNameType.ORIGINAL]);
            string dirName = "Markdown导出目录" + DateTime.Now.ToString("yyyy年MM月dd日HH时mm分ss秒fff毫秒");
            BasePath = Path.Combine(exportPath, dirName);
            RepeatFileName = FilePaths
                .Select(s => Path.GetFileNameWithoutExtension(s))
                .GroupBy(x => x)
                .Where(g => g.Count() > 1)
                .Select(y => y.Key)
                .ToList();
            Pbp.SetMaxValue(FilePaths.Count);
        }

        public override void InitComponent()
        {
            Pbp = new ProgressBarPanel();
            Ltp = new LogTextPanel();
        }
        public override void InitSize(int newWdith, int newHeight)
        {
            Pbp.Size = new Size(newWdith, Constants.EXECUTE_LINE_HEIGHT);
            Ltp.Size = new Size(newWdith, FrontUtil.GetFillHeight(newHeight, Pbp));
        }
        public override void InitLocation()
        {
            Pbp.Location = new Point(0, 0);
            FrontUtil.OnBottom(Ltp, Pbp, 0);
        }
        public override void InitEvent()
        {
            base.InitEvent();
            Load += async (s, e) =>
            {
                try { await ExecuteAll(Token.Token); }
                catch (OperationCanceledException) { }
            };
            FormClosing += (s, e) =>
            {
                if (!Pbp.IsFinished())
                {
                    DialogResult result = MessageBox.Show("程序正在打包中,确认关闭窗口？", "提示", MessageBoxButtons.YesNoCancel);
                    if (result == DialogResult.Yes) Token.Cancel();
                    else e.Cancel = true;
                }
            };
            FormClosed += (s, e) =>
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
            };
        }
        public override void AddComponent()
        {
            Controls.Add(Pbp);
            Controls.Add(Ltp);
        }

        public async Task ExecuteAll(CancellationToken token)
        {
            for (int i = 0; i < FilePaths.Count; i++)
            {
                token.ThrowIfCancellationRequested();
                Result res = FileUtil.ValidateFile(FilePaths[i]);
                if (!res.Status)
                {
                    UpdateLog($"{i + 1}.{res.Message}", Color.Yellow);
                    continue;
                }
                Markdown md = new Markdown(FilePaths[i]);
                UpdateLog($"{i + 1}.{md.FileName} ---------- 打包中...", Color.Blue);
                await Execute(md);
                UpdateLog($"{i + 1}.{md.FileName} ---------- 打包完成.", Color.Green);
                Pbp.PlusValue();
            }
        }
        //执行一个Markdown文件
        private async Task Execute(Markdown md)
        {
            string mdDirPath = GetUniqueDirectoryPath(BasePath, md.FileName);
            string picDirPath = Path.Combine(mdDirPath, Constants.PIC_DIR_NAME);
            Directory.CreateDirectory(md.Pictures.Any() ? picDirPath : mdDirPath);
            await Task.WhenAll(CreateRepeatTxt(md, mdDirPath), ExecuteLocalPicture(md, picDirPath), ExecuteUrlPicture(md, picDirPath));
            await FileUtil.WriteAllLinesAsync(Path.Combine(mdDirPath, $"{md.FileName}.md"), md.Contents);
        }
        private string GetUniqueDirectoryPath(string basePath, string name)
        {
            string directoryPath = Path.Combine(basePath, name);
            if (!Directory.Exists(directoryPath)) return directoryPath;
            return Enumerable.Range(1, int.MaxValue)
                .Select(i => Path.Combine(basePath, $"{name}({i})"))
                .First(path => !Directory.Exists(path));
        }
        private async Task CreateRepeatTxt(Markdown md, string mdDirPath)
        {
            if (RepeatFileName.Contains(md.FileName))
                await FileUtil.WriteAllLinesAsync(Path.Combine(mdDirPath, "重复文件信息.txt"), new[] { $"源文件路径:{md.FolderPath}\\{md.FileName}.md" });
        }

        //执行本地图片部分
        private async Task ExecuteLocalPicture(Markdown md, string picDirPath)
        {
            List<Picture> localPictures = md.Pictures.Where(p => p.Type == PictureType.LOCAL).ToList();
            if (!localPictures.Any()) return;
            IEnumerable<Task> tasks = localPictures.Select(async pic =>
            {
                await ConcurrencySemaphore.WaitAsync();
                try
                {
                    string name = GeneratePictureName(pic, md, localPictures.IndexOf(pic));
                    if (!File.Exists(pic.SrcPath))
                    {
                        UpdateLog($"第{pic.Index + 1}行 - 图片不存在", Color.Red);
                        return;
                    }
                    string typeStr = Path.GetExtension(pic.SrcPath);
                    UpdateContent(md, pic, name, typeStr);
                    await FileUtil.AsyncCopy(pic.SrcPath, Path.Combine(picDirPath, $"{name}{typeStr}"));
                }
                catch (OperationCanceledException)
                {
                    UpdateLog($"操作取消: {pic.SrcPath}", Color.Yellow);
                }
                catch (Exception ex)
                {
                    UpdateLog($"处理图片时出错: {pic.SrcPath} - {ex.Message}", Color.Red);
                }
                finally
                {
                    ConcurrencySemaphore.Release();
                }
            });
            await Task.WhenAll(tasks);
        }

        //执行网络图片部分
        private async Task ExecuteUrlPicture(Markdown md, string picDir)
        {
            List<Picture> netPictures = md.Pictures.Where(p => p.Type == PictureType.NET).ToList();
            if (!netPictures.Any()) return;
            IEnumerable<Task> tasks = netPictures.Select(async pic =>
            {
                await ConcurrencySemaphore.WaitAsync();
                try
                {
                    string name = GeneratePictureName(pic, md, netPictures.IndexOf(pic));
                    Result res = await FileUtil.DownloadImageAsync(pic.SrcPath, picDir, name);
                    if (!res.Status)
                    {
                        UpdateLog($"第{pic.Index + 1}行 - {res.Message}", Color.Red);
                        return;
                    }
                    UpdateContent(md, pic, name, Path.GetExtension(res.Message));
                }
                finally
                {
                    ConcurrencySemaphore.Release();
                }
            });
            try
            {
                await Task.WhenAll(tasks);
            }
            catch (AggregateException ex)
            {
                foreach (var innerEx in ex.InnerExceptions) UpdateLog($"下载过程中发生错误: {innerEx.Message}", Color.Red);
            }
            catch (Exception ex)
            {
                UpdateLog($"发生未知错误: {ex.Message}", Color.Red);
            }
        }

        // 生成图片名称的辅助方法
        private string GeneratePictureName(Picture pic, Markdown md, int index)
        {
            if (IsOriginalName)
                return pic.Type == PictureType.NET ? $"URL-{Guid.NewGuid()}" : Path.GetFileNameWithoutExtension(pic.SrcPath);
            else if (IsNumberName)
                return $"{index}".PadLeft(md.FillLength, '0');
            else
                return Guid.NewGuid().ToString();
        }
        // 线程安全的日志更新方法
        private void UpdateLog(string message, Color color)
        {
            if (Ltp.InvokeRequired) Ltp.Invoke(new Action(() => Ltp.AppendColoredText(message, color)));
            else Ltp.AppendColoredText(message, color);
        }
        //更新内容
        private void UpdateContent(Markdown md, Picture pic, string name, string typeStr)
        {
            md.Contents[pic.Index] = md.Contents[pic.Index].Replace(pic.MatchedStr, pic.GetReplaceAfterStr(name, $"{Constants.PIC_DIR_NAME}\\{name}{typeStr}"));
        }
    }
}
